package modelo;

/**
 * Representa cualquier operador en una expresion matematica
 */
public class Operador
{

    private String descripcion;
    // tipos de operadores
    private boolean unario;
    private boolean binario;
    private boolean ternario;
    private boolean asociativoDer;
    private boolean asociativoIzq;

    /**
     *
     * @param descripcion describe si el operador es unario, binario o ternario
     * tambien indica si es asociativo derecho o izquierdo
     */
    public Operador(String descripcion)
    {
        if (descripcion.charAt(0) == 'u')
        {
            unario = true;
            binario = false;
            ternario = false;
        } else if (descripcion.charAt(0) == 'b')
        {
            unario = false;
            binario = true;
            ternario = false;
        } else if (descripcion.charAt(0) == 't')
        {
            unario = false;
            binario = false;
            ternario = true;
        } else
        {
            throw new ErrorSintaxis("tipo de operador no especificado");
        }

        if (descripcion.charAt(1) == 'r')
        {
            asociativoDer = true;
            asociativoIzq = false;
        } else if (descripcion.charAt(1) == 'l')
        {
            asociativoDer = false;
            asociativoIzq = true;
        } else if (descripcion.charAt(1) == 'n')
        {
            asociativoDer = false;
            asociativoIzq = false;
        } else
        {
            throw new ErrorSintaxis("asociacion no especificada");
        }
        this.descripcion = descripcion;
    }

    /**
     * return@ el signo del operador sin los flags
     */
    public String getSigno()
    {
        return this.descripcion.substring(2, descripcion.length());
    }

    /**
     * @return el operador como string
     */
    @Override
    public String toString()
    {
        return this.getSigno();
    }

    /**
     * return@ el signo del operador con sus respectivos flags
     */
    public String getSignoConFlags(boolean conFlags)
    {
        if (conFlags)
        {
            return this.descripcion;
        } else
        {
            return getSigno();
        }
    }

    public boolean esUnario()
    {
        return this.unario;
    }

    public boolean esBinario()
    {
        return this.binario;
    }

    public boolean esTernario()
    {
        return this.ternario;
    }

    public boolean esAsociativoDerecha()
    {
        return this.asociativoDer;
    }

    public boolean esAsociativoIzq()
    {
        return this.asociativoIzq;
    }

    /**
     *
     * @param args los valores que se van a evaluar
     * @return el resultado de ejecutar este operador con los operandos
     */
    public double evaluar(double[] args)
    {
        if (descripcion.equals("bl+"))
        {
            return args[0] + args[1];
        } else if (descripcion.equals("bl-"))
        {
            return args[0] - args[1];
        } else if (descripcion.equals("bl*"))
        {
            return args[0] * args[1];
        } else if (descripcion.equals("bl/"))
        {
            return args[0] / args[1];
        }
        if (descripcion.equals("bl%"))
        {
            return args[0] % args[1];
        } else if (descripcion.equals("br^"))
        {
            if (args[1] < 0)
            {
                return 1 / Math.pow(args[0], args[1] * -1);
            } else return Math.pow(args[0], args[1]);
        } else if (descripcion.equals("un-"))
        {
            return -args[0];
        } else
        {
            throw new ErrorSintaxis("expresion mal formada");
        }
    }
}